﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace B121B {
    /// <summary>
    /// Bus class
    /// </summary>
    public class Bus: Vehicle, IHasHeightAndWeight, IHasSeatsAndSleepSeats, IRequireBigLicense {
        /// <summary>
        /// Bus constructor
        /// </summary>
        /// <param name="brand">Brand</param>
        /// <param name="model">Model</param>
        /// <param name="km">Distance driven</param>
        /// <param name="year">Production year</param>
        /// <param name="price">Price</param>
        /// <param name="motorSize">Size of motor</param>
        /// <param name="km_l">Travel distance on 1 liter of fuel</param>
        /// <param name="fueltype">Fueltype</param>
        /// <param name="seats">Number of seats</param>
        /// <param name="sleepseats">Number of sleeping seats</param>
        /// <param name="hasToilet">If the bus has a toilet</param>
        /// <param name="height">Heght (in meters)</param>
        /// <param name="weight">Weight (in kg)</param>
        public Bus(string brand, string model, int km, DateTime year, double price, double motorSize, double km_l, Fuel fueltype, int seats, int sleepseats, bool hasToilet, double height, int weight)
            : base(brand, model, km, year, price, motorSize, km_l, fueltype) {
            Seats = seats;
            SleepSeats = sleepseats;
            HasToilet = hasToilet;
            Height = height;
            Weight = weight;
            VehicleType = VehicleTypes.Bus;
        }

        #region Properties
        /// <summary>
        /// Number of seats
        /// </summary>
        public int Seats {
            get { return _Seats; }
            set {
                if (value < 0) { // Check for valid amount of seats
                    throw new ArgumentOutOfRangeException("A bus cannot have a negative amount of seats");
                } else {
                    _Seats = value;
                }
            }
        }
        private int _Seats;

        /// <summary>
        /// Number of sleep seats
        /// </summary>
        public int SleepSeats {
            get { return _SleepSeats; }
            set {
                if (value < 0) { // Check for valid amount of sleeping seats
                    throw new ArgumentOutOfRangeException("A bus cannot have a negative amount of sleeping seats");
                } else {
                    _SleepSeats = value;
                }
            }
        }
        private int _SleepSeats;

        /// <summary>
        /// Does the bus have a toilet
        /// </summary>
        public bool HasToilet { get; set; }

        /// <summary>
        /// Height of the bus (in meters)
        /// </summary>
        public double Height {
            get { return _Height; }
            set {
                if (value < 0) { // Check for valid height
                    throw new ArgumentOutOfRangeException("A bus cannot have a negative height");
                } else {
                    _Height = value;
                }
            }
        }
        private double _Height;

        /// <summary>
        /// Weight of the bus
        /// </summary>
        public int Weight {
            get { return _Weight; }
            set {
                if (value < 0) { // Check for valid weight
                    throw new ArgumentOutOfRangeException("A bus cannot have a negative weight");
                } else {
                    _Weight = value;
                }
            }
        }
        private int _Weight;

        /// <summary>
        /// Size of the motor
        /// </summary>
        public override double MotorSize {
            get { return _MotorSize; }
            set {
                if (!IsMotorSizeOkay(4.2, 14.2, value)) { // Check for valid motor size
                    throw new ArgumentOutOfRangeException();
                } else {
                    _MotorSize = value;
                }
            }
        }
        private double _MotorSize;

        /// <summary>
        /// Max speed
        /// </summary>
        public override int MaxSpeed { get { return 120; } } // Max speed is locked to 120, as per assignment

        /// <summary>
        /// Fueltype
        /// </summary>
        public override Fuel FuelType {
            get { return _FuelType; }
            protected set {
                if (value != Fuel.Diesel) { // Checks if the fueltype is diesel
                    throw new ArgumentException("Busses run on diesel!"); // Busses only runs on diesel, as per assignment
                } else {
                    _FuelType = value;
                }
            }
        }
        private Fuel _FuelType;

        /// <summary>
        /// License of the driver
        /// </summary>
        public DriversLicense License {
            get { return _License; }
            set {
                if (value < DriversLicense.C) { // Check for valid license
                    throw new ArgumentException("Driver must have at least a C license"); // A driver must have at least a C license to drive a truck, as per assignment
                } else {
                    _License = value;
                }
            }
        }
        private DriversLicense _License;
        #endregion

        #region Override Equals
        public override bool Equals(object obj) {
            if (obj == null) { return false; } // Check for null

            // We don't check for reference equality

            if (this.GetType() != obj.GetType()) { return false; } // Same type?

            return Equals((Vehicle)obj); // More specific check
        }
        public bool Equals(Bus obj) {
            if (obj == null) { return false; }

            return // Check all values
                base.Equals(obj) &&
                this.Seats == obj.Seats &&
                this.SleepSeats == obj.SleepSeats &&
                this.HasToilet == obj.HasToilet &&
                this.Height == obj.Height &&
                this.Weight == obj.Weight;
        }
        public override int GetHashCode() {
            return base.GetHashCode(); // We do not check has code, as we check on values only
        }

        public static bool operator ==(Bus obj1, Bus obj2) {
            if (ReferenceEquals(obj1, null)) {
                return ReferenceEquals(obj2, null); // Both null, equal, otherwise not
            }
            return obj1.Equals(obj2);
        }
        public static bool operator !=(Bus obj1, Bus obj2) {
            return !(obj1 == obj2);
        }
        #endregion

        /// <summary>
        /// Shows the bus information, formatted for console output
        /// </summary>
        /// <returns>Bus information as a string</returns>
        public override string ToString() {
            return base.ToString() +
                "  Seats: " + Seats + Environment.NewLine +
                "  SleepSeats: " + SleepSeats + Environment.NewLine +
                "  Toilet: " + (HasToilet ? "Yes" : "No") + Environment.NewLine +
                "  Height: " + Height + Environment.NewLine +
                "  Weight: " + Weight;
        }
    }
}